import {
  Component,
  OnInit,
  OnDestroy,
  Input,
  ChangeDetectorRef,
  EventEmitter,
} from '@angular/core';
import { Observable, Subject, merge } from 'rxjs';
import { startWith, switchMap } from 'rxjs/operators';

import {
  OverlayEntry,
  DropdownAnimation,
  DEFAULT_CASCADE_POSITIONS,
  Direction,
  composePositionSet,
} from '../shared/shared';

import { CascadeItemComponent } from './cascade-item.component';

@Component({
  selector: 'fui-cascade',
  templateUrl: './cascade.component.html',
  animations: [
    DropdownAnimation,
  ],
})
export class CascadeComponent extends OverlayEntry implements OnInit, OnDestroy {
  /** Direction to expand cascade. */
  @Input() direction: Direction = 'bottom';

  /** Custom class name */
  @Input() customClass: string;

  animationDirection = 'bottom';

  /** Whether the cascade is a sub-cascade. */
  isSubCascade = false;

  closed = new EventEmitter<void | 'click'>();

  items: CascadeItemComponent[] = [];

  itemChanges = new Subject<CascadeItemComponent[]>();

  classMap = {};

  constructor(
    // protected ngZone: NgZone,
    private changeDetectionRef: ChangeDetectorRef,
  ) {
    super();
  }

  ngOnInit() {
    this.positions = composePositionSet(this.direction);
    this.setPosition(this.direction);
  }

  ngOnDestroy() {
    this.closed.complete();
  }

  hovered(): Observable<CascadeItemComponent> {
    return this.itemChanges.pipe(
      startWith(this.items),
      switchMap(items => merge(...items.map(item => item.hovered))),
    );
  }

  hideCascade(event?: void | 'click') {
    this.closed.emit(event);
    this.hide();
  }

  clickCascade(triggersSubCascade: boolean) {
    if (!triggersSubCascade) {
      this.hideCascade('click');
    }
  }

  setPosition(direction: Direction) {
    this.classMap = {
      [`fui-cascade-${this.toShortDirection(direction)}`]: true,
    };
    if (this.customClass) {
      this.classMap[this.customClass] = true;
    }

    this.animationDirection = this.direction
      .replace(/[A-Z]/g, (match) => '__' + match.toLowerCase())
      .split('__')[0];

    // 基于某些原因重渲染失败，需要手动触发。在其他项目Angular6.0 + CDK6.0无此问题.
    // TODO: 升级6.0之后移除
    this.changeDetectionRef.detectChanges();
  }

  setSubCascadePosition() {
    this.positions = DEFAULT_CASCADE_POSITIONS;
    this.direction = 'right';
  }

  toShortDirection(direction: string) {
    const dirSnakes = this.toSnake(direction);
    return dirSnakes.split('-')[0];
  }

  addItem(item: CascadeItemComponent) {
    if (this.items.indexOf(item) === -1) {
      this.items.push(item);
      this.itemChanges.next(this.items);
    }
  }

  removeItem(item: CascadeItemComponent) {
    const index = this.items.indexOf(item);

    if (this.items.indexOf(item) > -1) {
      this.items.splice(index, 1);
      this.itemChanges.next(this.items);
    }
  }
}
